package com.easyidea.its.domain.repository.base.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.easyidea.its.domain.model.IBean;
import com.easyidea.its.domain.repository.base.BaseRepository;
import com.easyidea.its.domain.repository.base.ExtendPersistenceIF;
import com.infowarelab.common.log.Log;
import com.infowarelab.common.log.LogFactory;
import com.infowarelab.persistence.filter.base.Filter;

public class BaseRepositoryImpl<T> extends HibernateDaoSupport implements BaseRepository<T> {

	private static final Log log = LogFactory.getLog(BaseRepositoryImpl.class);

	private Class<T> clazz;

	/**
	 * persistence interface.
	 */
	protected ExtendPersistenceIF persistence;


	public Session getCurrentSession() {
		return getSession();
	}
	
	@SuppressWarnings("unchecked")
	public BaseRepositoryImpl() {
		this.clazz = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}
	@SuppressWarnings("unchecked")
	public <E> E save(E bean) {
		Serializable s = persistence.create(bean);
		return (E) persistence.get(clazz, s);
	}

	public <E> void update(E bean) {
		persistence.update(bean);
	}
	
	public <E> void merge(E bean) {
		persistence.merge(bean);
	}

	public void removeBeanByLogic(int id) {
		this.removeBeanByLogic(clazz, id);

	}

	@SuppressWarnings("unchecked")
	public <E> void removeBeanByLogic(Class<E> clazz, int id) {
		E bean = (E) persistence.get(clazz, id);
		persistence.delete(bean);
	}

	public void removeBean(int id) {
		this.removeBean(clazz, id);
	}

	@SuppressWarnings("unchecked")
	public <E extends IBean> E getBeanById(Class<E> clazz, int id) {
		E bean = (E) persistence.get(clazz, id);
		return bean;

	}

	/**
	 * @return the persistence
	 */
	public ExtendPersistenceIF getPersistence() {
		return persistence;
	}

	/**
	 * @param persistence
	 *            the persistence to set
	 */
	public void setPersistence(ExtendPersistenceIF persistence) {
		this.persistence = persistence;
	}

	public <E> void removeBean(Class<E> clazz, int id) {
		E bean = this.getBeanById(clazz, id);
		if (bean != null) {
			persistence.deleteTrue(bean);
		}
	}

	public T getBeanById(int id) {
		return this.getBeanById(clazz, id);
	}

	@SuppressWarnings("unchecked")
	private <E> E getBeanById(Class<E> clazz, int id) {
		return (E) persistence.get(clazz, id);
	}

	public Collection listBeans(Filter filter) {
		return persistence.query(filter);
	}

	public int countBeans(Filter filter) {
		return persistence.count(filter);
	}

	public Collection executeHqlCol(String queryStr) {
		return persistence.executeSql(queryStr);
	}

	public Collection executePureSqlCol(String queryStr) {
		return persistence.executePureSql(queryStr);
	}

	public Collection executePureSqlCol(String queryStr, Object[] values) {
		return persistence.executePureSql(queryStr, values);
	}

	public Collection executePureSqlCol(String queryStr, Object[] values,
			int startAtIndex, int count) {
		return persistence
				.executePureSql(queryStr, values, startAtIndex, count);
	}

	@SuppressWarnings("deprecation")
	public boolean executePureSql(String sql) {
		Session session = this.getCurrentSession();
		Connection connection = session.connection();

		PreparedStatement ps = null;
		try {
			ps = connection.prepareStatement(sql);
			ps.execute();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		if (ps != null) {
			try {
				ps.close();
			} catch (SQLException e) {
				log.error(e);
			}
		}
		if (connection != null) {
			try {
				connection.close();
			} catch (SQLException e) {
				log.error(e);
			}
		}
		session.flush();
		return true;
	}

	public Criteria createCriteria() {
		Criteria criteria = this.getCurrentSession()
				.createCriteria(clazz);
		return criteria;
	}

	public int countBeans(Criteria criteria) {
		criteria.setProjection(Projections.rowCount());
		int count = (Integer) criteria.uniqueResult();
		criteria.setProjection(null);
		return count;
	}

	public Criteria createUndeleteCriteria() {
		Criteria criteria = createCriteria();
		criteria.add(Restrictions.eq("deleted", false));
		return criteria;
	}

	public Collection listBeans(Criteria criteria, int startAtIndex, int size) {
		if (startAtIndex > 0) {
			criteria.setFirstResult(startAtIndex);
		}
		if (size > 0) {
			criteria.setMaxResults(size);
		}
		return criteria.list();
	}
	
	@SuppressWarnings("unchecked")
	public Collection<T> listBeansBySql(String sql, int start, int size) {
		Query query = this.getCurrentSession().createSQLQuery(sql);
		query.setFirstResult(start >= 0 ? start : 0);
		if (start > 0) {
			query.setFirstResult(start);
		}
		if (size > 0) {
			query.setMaxResults(size);
		}
		return query.list();
	}
	public void saveOrUpdateBean(T bean) {
		this.getSessionFactory().getCurrentSession().saveOrUpdate(bean);
	}
	public boolean isRepeated(String propertyName, String propertyValue, Serializable id,boolean isIncludeDeleted) {
		Criteria criteria=createCriteria()
			.add(Expression.eq(propertyName, propertyValue))
			.add(Expression.ne("id", id));
		if (!isIncludeDeleted) {
			criteria.add(Expression.eq("deleted", false));
		}
		if (criteria.list().size() > 0) {
			return true;
		}
		return false;
	}
	
}
